/*******************************************************************************
 * Copyright (c) 2001, 2002 Boris Pruessmann and others. All rights reserved.
 * This program and the accompanying materials are made available under the
 * terms of the Common Public License v0.5 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors: Boris Pruessmann - Initial implementation.
 ******************************************************************************/
package net.sourceforge.perforce.ui.action;

import com.google.common.collect.Lists;

import net.sourceforge.perforce.core.PerforceCorePlugin;
import net.sourceforge.perforce.core.PerforceException;
import net.sourceforge.perforce.core.api.IPerforceServer;
import net.sourceforge.perforce.core.api.IResolveResult;
import net.sourceforge.perforce.core.api.ResolveTypeEnum;
import net.sourceforge.perforce.core.internal.P4TeamProvider;
import net.sourceforge.perforce.core.resources.RemoteResource;
import net.sourceforge.perforce.ui.PerforceCompareEditorInput;
import net.sourceforge.perforce.ui.PerforceResourceEditionNode;
import net.sourceforge.perforce.ui.PerforceResourceNode;

import org.eclipse.compare.CompareUI;
import org.eclipse.compare.internal.CompareUIPlugin;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Display;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.core.TeamException;

import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
import java.util.List;

/**
 * @version $Revision: 488 $
 * @author <a href="mailto:bpruessmann@users.sourceforge.net">Boris
 *         Pruessmann</a>
 */
public class CompareWithHeadAction extends PerforceAction {
  //----------------------------------------------------------------------------
  // -- Public Methods
  @Override
  protected boolean isEnabled() {
    IResource[] resources = getSelectedResources();

    List<IResource> diffableResources = getDiffableResoures(resources);
    return !diffableResources.isEmpty();
  }

  @Override
  public void run(IAction action) {
    run(new IRunnableWithProgress() {
      public void run(IProgressMonitor monitor) throws InvocationTargetException {
        triggerCompareUI();

        try {
          final IResource[] resources = getSelectedResources();

          for (Iterator<IResource> i = getDiffableResoures(resources).iterator(); i.hasNext();) {
            final IResource resourceToDiff = i.next();
            diffResource(resourceToDiff);
          }
        } catch (TeamException e) {
          throw new InvocationTargetException(e);
        } catch (CoreException e) {
          throw new InvocationTargetException(e);
        }
      }

      private void diffResource(final IResource resourceToDiff) throws CoreException,
          TeamException, PerforceException {
        if (!resourceToDiff.isSynchronized(IResource.DEPTH_INFINITE)) {
          resourceToDiff.refreshLocal(IResource.DEPTH_INFINITE, null);
        }

        P4TeamProvider provider = P4TeamProvider.getProvider(resourceToDiff);
        IPerforceServer server = provider.getPerforceServer();

        RemoteResource tempAncestorResource = null;
        if (resourceToDiff instanceof IFile) {
          tempAncestorResource =
              provider.getRemoteTree(resourceToDiff, "#" + compareRevision(server, resourceToDiff),
                  new NullProgressMonitor());
        }
        final RemoteResource ancestorResource = tempAncestorResource;
        final RemoteResource remoteResource =
            provider.getRemoteTree(resourceToDiff, "#head", new NullProgressMonitor());

        getShell().getDisplay().asyncExec(new Runnable() {
          public void run() {
            PerforceCompareEditorInput input = null;
            if (ancestorResource != null) {
              input =
                  new PerforceCompareEditorInput(new PerforceResourceNode(resourceToDiff),
                      new PerforceResourceEditionNode(remoteResource),
                      new PerforceResourceEditionNode(ancestorResource));
            } else {
              input =
                  new PerforceCompareEditorInput(new PerforceResourceNode(resourceToDiff),
                      new PerforceResourceEditionNode(remoteResource), null);
            }

            CompareUI.openCompareEditor(input);
          }

        });
      }
    }, PROGRESS_DIALOG, false);
  }

  // ---------------------------------------------------------------------------
  // Protected Methods

  protected String compareRevision(IPerforceServer server, IResource resourceToDiff)
      throws PerforceException {
    IResolveResult[] resolveResults =
        server.resolve(resourceToDiff.getLocation().toOSString(), ResolveTypeEnum.AUTOMATIC,
            IPerforceServer.RESOLVE_SIMULATE);
    if (resolveResults.length == 1) {
      int revision = resolveResults[0].getRevision().intValue() - 1;
      return String.valueOf(revision);
    }
    return "have";
  }


  //----------------------------------------------------------------------------
  // - Private Methods

  protected List<IResource> getDiffableResoures(IResource[] resources) {
    List<IResource> diffableResources = Lists.newArrayList();
    for (int i = 0; i < resources.length; i++) {

      RepositoryProvider tempProvider = RepositoryProvider.getProvider(resources[i].getProject());
      if (tempProvider == null || !tempProvider.getID().equals(PerforceCorePlugin.getTypeId()))
        break;
      P4TeamProvider provider = (P4TeamProvider) tempProvider;
      if (provider.hasRemote(resources[i])) {
        diffableResources.add(resources[i]);
      }
    }
    return diffableResources;
  }

  /**
   * This method will trigger the load of the Compare Component within the
   * display thread
   */
  private void triggerCompareUI() {
    Display display = getShell().getDisplay();
    display.syncExec(new Runnable() {
      /** @see java.lang.Runnable#run() */
      public void run() {
        CompareUIPlugin.getDefault();
      }
    });
  }

}
